package com.lyl.novel.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.page.PageMethod;
import com.lyl.example.common.exception.BizException;
import com.lyl.novel.common.utils.ContextHolderUtils;
import com.lyl.novel.common.utils.QuartzUtils;
import com.lyl.novel.dao.TaskDao;
import com.lyl.novel.model.dto.TaskDTO;
import com.lyl.novel.model.dto.TaskListDTO;
import com.lyl.novel.model.entity.Task;
import com.lyl.novel.service.TaskService;
import com.lyl.novel.third.excel.entity.TaskExcel;
import lombok.RequiredArgsConstructor;
import org.quartz.Job;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * (Task)表服务实现类
 *
 * @author Mr Luo
 * @since 2022-08-22 16:10:24
 */
@Service("taskService")
@RequiredArgsConstructor
public class TaskServiceImpl extends ServiceImpl<TaskDao, Task> implements TaskService {
    private final Map<String, Job> jobMap;

/*    @Override
    public boolean addJob(TaskDTO dto) {
        Task task = BeanUtil.copyProperties(dto, Task.class);
        boolean result;
        if (QuartzUtils.checkExists(task)) {
            result = QuartzUtils.updateJob(task);
            task.setUpdateUser(dto.getUserName());
        } else {
            result = QuartzUtils.addJob(task);
            task.setCreateUser(dto.getUserName());
        }
        updateTask(task);
        return result;
    }

    @Override
    public boolean stopJob(Long id) {
        Task task = getById(id);
        Assert.notNull(task, () -> new BizException("定时任务不存在"));
        boolean result = false;
        if (QuartzUtils.checkExists(task)) {
            result = QuartzUtils.pauseJob(task);
        }
        updateTask(task);
        return result;
    }

    @Override
    public boolean resumeJob(Long id) {
        Task task = getById(id);
        Assert.notNull(task, () -> new BizException("定时任务不存在"));
        boolean result;
        if (QuartzUtils.checkExists(task)) {
            result = QuartzUtils.resumeJob(task);
        } else {
            result = QuartzUtils.addJob(task);
        }
        updateTask(task);
        return result;
    }

    private void updateTask(Task task) {
        task.setJobStatus(QuartzUtils.getState(task.getJobName(), task.getJobGroup()));
        saveOrUpdate(task);
    }

    @Override
    public boolean runOnce(Long id) {
        Task task = getById(id);
        Assert.notNull(task, () -> new BizException("定时任务不存在"));
        boolean runOnce = QuartzUtils.runOnce(task);
        updateTask(task);
        return runOnce;
    }*/

    @Override
    public boolean addJob(TaskDTO dto) {
        Task task = BeanUtil.copyProperties(dto, Task.class);
        boolean result;
        if (QuartzUtils.checkExists(task)) {
            result = QuartzUtils.updateJob(task);
            task.setUpdateUser(dto.getUserName());
        } else {
            result = QuartzUtils.addJob(task);
            task.setCreateUser(dto.getUserName());
        }
        updateTask(task);
        return result;
    }

    @Override
    public boolean stopJob(Long id) {
        return handlerTask(id, task -> QuartzUtils.checkExists(task) && QuartzUtils.stopJob(task));
    }

    @Override
    public boolean resumeJob(Long id) {
        return handlerTask(id, task -> QuartzUtils.checkExists(task) ? QuartzUtils.resumeJob(task) : QuartzUtils.addJob(task));
    }

    @Override
    public boolean runOnce(Long id) {
        return QuartzUtils.runOnce(getById(id));
    }

    @Override
    public boolean delJob(Long id) {
        Task task = getById(id);
        Assert.notNull(task, () -> new BizException("定时任务不存在"));
        boolean result = QuartzUtils.checkExists(task) && QuartzUtils.deleteJob(task);
        removeById(task);
        return result;
    }

    @Override
    public PageInfo<Task> pageList(Integer pageNo, Integer pageSize, TaskListDTO dto) {
        PageMethod.startPage(pageNo, pageSize);
        List<Task> taskList = lambdaQuery()
                .like(ObjectUtil.isNotEmpty(dto.getJobName()), Task::getJobName, dto.getJobName())
                .like(ObjectUtil.isNotEmpty(dto.getJobGroup()), Task::getJobGroup, dto.getJobGroup())
                .like(ObjectUtil.isNotEmpty(dto.getJobStatus()), Task::getJobStatus, dto.getJobStatus())
                .like(ObjectUtil.isNotEmpty(dto.getBeanClass()), Task::getBeanClass, dto.getBeanClass())
                .list();
        return PageInfo.of(taskList);
    }

    @Override
    public Set<String> getJobClassList() {
        return jobMap.values()
                .stream().map(Job::getClass)
                .map(Class::getName)
                .collect(Collectors.toSet());
    }

    @Override
    public void downloadExcel(Integer pageNo, Integer pageSize) throws IOException {
        List<Task> list = pageList(pageNo, pageSize, new TaskListDTO()).getList();
        List<TaskExcel> taskExcels = list.stream().map(task -> BeanUtil.copyProperties(task, TaskExcel.class)).collect(Collectors.toList());
        HttpServletResponse response = ContextHolderUtils.getResponse();
        assert response != null;
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = URLEncoder.encode("定时任务", "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        EasyExcelFactory.write(response.getOutputStream(), TaskExcel.class)
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                .sheet().doWrite(taskExcels);
    }

    public boolean handlerTask(Long id, Predicate<Task> handler) {
        Task task = getById(id);
        Assert.notNull(task, () -> new BizException("定时任务不存在"));
        boolean result = handler.test(task);
        updateTask(task);
        return result;
    }

    private void updateTask(Task task) {
        task.setJobStatus(QuartzUtils.getState(task.getJobName(), task.getJobGroup()));
        saveOrUpdate(task);
    }
}

